#ifndef EXT2_H
#define EXT2_H

#include "main.h"
#include "settings.h"
#include "structs.h"
#include "fs.h"
#include "memory.h"
#include "string.h"
#include "print.h"
#include "lock.h"

typedef struct {
	char *cache;
	uint32_t blocknum;
	char device;		// Enthält die gemountete Gerätenummer, wird später mal verwendet
} ext_cache_t;

/* Liest den Superblock des ext2 Dateisystems aus.
 * Parameter: Keine
 * Rückgaben: TRUE bei Erfolg, bei Fehlern (zB wenn das Gerät kein ext2 Gerät ist) FALSE
 */
BOOL ext_read_superblock ();

/* Gibt die Größe eines Blocks zurück
 * Parameter: Pointer auf einen Superblock
 * Rückgaben: Blockgröße in Bytes
 */
inline uint32_t ext_get_block_size (ext_superblock_t *);

/* Liest einen Block
 * Parameter: Pointer auf eine Superblock Struktur, Blocknummer, Puffer
 * Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
 */
BOOL ext_read_block (ext_superblock_t *, uint32_t, void *);

/* Schreibt einen Block
 * Parameter: Pointer auf eine Superblock Struktur, Blocknummer, Puffer
 * Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
 */
BOOL ext_write_block (ext_superblock_t *, uint32_t, void *);

/* Liest die Block Gruppen Deskriptor Tabelle aus
 * Parameter: Pointer zu einer Superblock Struktur, Pointer auf einer BGDT Struktur
 * Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
 */
BOOL ext_read_block_group_desc (ext_superblock_t *, ext_group_desc_t *);

/* Sucht einen freien Block und markiert diesen als benutzt
 * Parameter: Pointer auf einen Superblock, Pointer auf eine BGDT
 * Rückgaben: Bei Erfolg einen Block, ansonsten 0
 */
uint32_t ext_find_free_block (ext_superblock_t *, ext_group_desc_t *);

/* Gibt eine Liste mit Blöcken zurück
 * Parameter: Zeiger auf einen Superblock, Zeiger auf einen iNode
 * Rückgaben: Pointer auf ein uint32_t Array, der alle Blöcke enthält
 */
uint32_t *ext_get_block_list (ext_superblock_t *, ext_inode_table_t *);

/* Schreibt eine Blockliste in einen iNode
 * Parameter: Zeiger auf einen Superblock, Zeiger auf eine BGDT, Zeiger auf einen iNode, Blockliste
 * Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
 */
BOOL ext_write_block_list (ext_superblock_t *, ext_group_desc_t *, ext_inode_table_t *, uint32_t *);
	
/* Ändert den Status eines Blocks in einer Block Group
 * Parameter: Pointer zu einer Superblock Struktur, Pointer zu einer BGDT Struktur, Block, Status (1 = Benutzt, 0 = Frei)
 * Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
 */
BOOL ext_change_block_status (ext_superblock_t *, ext_group_desc_t *, uint32_t, uint8_t);

/* Ändert den Status eines iNode in einer Block Group
 * Parameter: Pointer auf eine Superblock Struktur, Pointer auf eine BGDT Struktur, Block, Status (1 = Benutzt, 0 = Frei)
 * Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
 */
BOOL ext_change_inode_status (ext_superblock_t *, ext_group_desc_t *, uint32_t, uint8_t);

/* Aktualisiert die Daten eines iNodes
* Parameter: Zeiger auf einen Superblock, Zeiger auf eine BGDT, iNode Index, 
* Zeiger auf einen iNode, Blockliste, Dateigröße, Zugegriffen, beschrieben, gelöscht
* Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
*/
BOOL ext_update_inode (ext_superblock_t *, ext_group_desc_t *, uint32_t, ext_inode_table_t *,
		       uint32_t *, uint32_t, BOOL, BOOL, BOOL);
/* Überprüft ob ein iNode frei ist oder nicht
 * Parameter: Pointer auf eine Superblock Struktur, Pointer auf eine BGDT Struktur, Block 
 * Rückgaben: Wenn der iNode frei ist FALSE, wenn er in Gebrauch ist TRUE
 */
BOOL ext_inode_in_use (ext_superblock_t *, ext_group_desc_t *, uint32_t);

/* Liest einen iNode aus
 * Parameter: Pointer auf eine Superblock Struktur, Block der den iNode enthält, Index im Block, Pointer auf eine iNode Struktur
 * Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
 */
BOOL ext_read_inode (ext_superblock_t *, ext_group_desc_t *, uint32_t, ext_inode_table_t *);

/* Durchsucht die Dir Tables nach einen iNode.
 * Parameter: Gesuchter iNode, Auszuschliessender Index (wenn keiner ausgeschlossen werden soll, ist dieser Wert = 0xFFFFFFFF)
 * Rückgaben: Wenn der iNode gefunden wurde TRUE, ansonsten FALSE
 */
BOOL ext_find_inode (uint32_t, uint32_t);

/* Liest die Directory Tables aus und macht die Einträge dem VFS bekannt
 * Parameter: Pointer auf eine Superblock Struktur, Pointer auf eine BGDT Struktur,
 *	Pointer auf eine iNode Struktur die die Directory Tables enthält,
 *	Pointer auf eine fs_entry Struktur die als Übergeordnetes Verzeichniss fungiert
 *	Rückgaben: Bei Erfolg TRUE, ansonsten FALSE
 */
BOOL ext_read_dir_tables (ext_superblock_t *, ext_group_desc_t *, ext_inode_table_t *, struct fs_entry *);

/* Startet den ext2 Treiber
 * Parameter: String auf ein Blockgerät
 * Rückgaben: Keine
 */
void ext_start (const char *);

/* Kopiert einen Block in den Cache
 * Parameter: Zeiger auf einen Superblock, Block nr, Zeiger auf einen Block
 * Rückgaben: Keine
 */
void ext_cache_block (ext_superblock_t *, uint32_t, char *);

/* Sucht einen Block im Cache
 * Parameter: Device ID, Block nr
 * Rückgaben: Wenn der Block gefunden wurde einen Zeiger auf ihn, ansonsten NULL
 */
char *ext_get_block_cache (char, uint32_t);

/* Löscht einen Block aus dem Cache
 * Parameter: Device ID, Block nr
 * RÜckgaben: Keine
 */
void ext_remove_cache_block (char, uint32_t);

/// VFS
FILE *ext_open (const char *, struct fs_entry *, const char *);
size_t ext_read (FILE *, char *, size_t);
size_t ext_write (FILE *, void *, size_t);
int ext_close (FILE *);
int ext_seek (FILE *, int, int);
size_t ext_tell (FILE *);
BOOL ext_init (char);
BOOL ext_deinit ();

#endif
